class LRU {
    constructor(capacity = 3) {
        this.capacity = capacity
        this._cacheData = {}
        this._cacheKeys = [] // old -> new
    }

    has(key) {
        return this._cacheKeys.includes(key)
    }

    refresh(key) {
        const keyList = this._cacheKeys
        const index = keyList.findIndex(ekey => ekey === key)
        keyList.splice(index, 1)
        keyList.push(key)
    }

    get(key) {
        if (!this.has(key)) {
            return 
        }

        // refresh key, change key order
        this.refresh(key)
        const res = this._cacheData[key]
        this.log('[get]')
        return res
    }

    set(key, val) {
        
        if (this.has(key)) {
            this.refresh(key)
            this._cacheData[key] = val
        } else {
            // add new key

            // overflow
            if (this.capacity === this._cacheKeys.length) {
                this.del(this._cacheKeys[0])
            }
            this._cacheKeys.push(key)
            this._cacheData[key] = val
        }

        this.log('[set]')
    }

    del(key) {
        const index = this._cacheKeys.findIndex(ekey => ekey === key)
        this._cacheKeys.splice(index, 1)
        delete this._cacheData[key]
    }

    clear() {
        this._cacheData = {}
        this._cacheData = []
    }

    log(prefix = '') {
        console.log(prefix, 'cacheData', this._cacheData)
        console.log(prefix, 'cacheKeys', this._cacheKeys)
        console.log()
    }
}


// Map会保持键值对的插入顺序， [...map.keys()] 得到的列表是和插入顺序一致的
class LRUEasy {
    constructor(capacity = 3) {
        this.capacity = capacity
        this._cache = new Map()
    }

    refresh(key, newVal) {
        const oldVal = this._cache.get(key)
        const val = newVal === undefined ? oldVal : newVal
        this._cache.delete(key)
        this._cache.set(key, val)
        return val
    }

    get(key) {
        if (!this._cache.has(key)) {
            return
        }

        const val = this.refresh(key)
        this.log('[get]')
        return val
    }

    set(key, val) {
        if (this._cache.has(key)) {
            this.refresh(key, val)
        } else {
            // add new

            // overflow
            if (this.capacity === this._cache.size) {
                const oldKey = [...this._cache.keys()].shift()
                console.log("🚀 ~ file: lru.js:103 ~ LRUEasy ~ set ~ oldKey:", oldKey)
                this._cache.delete(oldKey)
            }

            this._cache.set(key, val)
        }

        this.log('[set]')
    }

    log(prefix = '') {
        console.log(prefix, this._cache, [...this._cache.keys()])
        console.log()
    }
}


function test(LRUCache) {
    const lru = new LRUCache()
    lru.set('one', 1)
    lru.set('two', 2)
    lru.set('three', 3)
    console.log("lru.get('two')::", lru.get('two'))
    lru.set('four', 4)
    lru.set('three', 30)
}



// test(LRU)
test(LRUEasy)